<?php

namespace app\middleware;

use think\Request;
use think\Response;
use app\model\UserLog;
use Closure;

class Log
{
    /**
     * 处理请求
     */
    public function handle(Request $request, Closure $next)
    {
        // 记录请求开始时间
        $startTime = microtime(true);

        // 执行请求
        $response = $next($request);

        // 计算请求耗时
        $duration = round((microtime(true) - $startTime) * 1000, 2);

        // 记录访问日志
        $this->logAccess($request, $response, $duration);

        return $response;
    }

    /**
     * 记录访问日志
     */
    private function logAccess(Request $request, Response $response, $duration)
    {
        // 只记录重要的操作
        $action = $this->getActionFromRequest($request);
        if (!$action) {
            return;
        }

        $userId = $request->userId ?? null;
        $responseData = null;

        // 解析响应数据
        try {
            $responseBody = $response->getContent();
            $responseData = json_decode($responseBody, true);
        } catch (\Exception $e) {
            // 忽略解析错误
        }

        // 构建日志数据
        $logData = [
            'user_id' => $userId,
            'action' => $action,
            'description' => $this->getActionDescription($action, $request),
            'ip' => $request->ip(),
            'platform' => $request->param('platform', 'unknown'),
            'device_id' => $request->param('device_id'),
            'user_agent' => $request->header('user-agent'),
            'extra_data' => [
                'method' => $request->method(),
                'url' => $request->url(true),
                'params' => $this->filterSensitiveData($request->param()),
                'response_code' => $responseData['code'] ?? $response->getCode(),
                'duration' => $duration,
            ],
        ];

        // 异步记录日志（避免影响响应速度）
        $this->asyncLog($logData);
    }

    /**
     * 从请求中获取操作类型
     */
    private function getActionFromRequest(Request $request)
    {
        $pathInfo = $request->pathinfo();
        $method = $request->method();

        // 根据路径和方法判断操作类型
        $actionMap = [
            // 认证相关
            'POST:auth/login' => 'login',
            'POST:auth/logout' => 'logout',
            'POST:auth/register' => 'register',
            'POST:auth/wechat-login' => 'wechat_login',
            'POST:auth/alipay-login' => 'alipay_login',
            'POST:auth/douyin-login' => 'douyin_login',
            'POST:auth/bind' => 'bind_oauth',
            'DELETE:auth/unbind' => 'unbind_oauth',

            // 用户相关
            'PUT:user/password' => 'change_password',
            'PUT:user/info' => 'update_profile',
            'DELETE:user/devices' => 'delete_device',

            // 账号相关
            'POST:accounts' => 'create_account',
            'PUT:accounts' => 'update_account',
            'DELETE:accounts' => 'delete_account',
            'POST:accounts/copy-password' => 'copy_password',
            'POST:accounts/batch-delete' => 'batch_delete_account',
            'GET:accounts/export' => 'export_data',

            // 分类相关
            'POST:categories' => 'create_category',
            'PUT:categories' => 'update_category',
            'DELETE:categories' => 'delete_category',

            // 系统相关
            'POST:system/feedback' => 'feedback',
        ];

        $key = $method . ':' . trim($pathInfo, '/');

        // 支持动态路由匹配
        foreach ($actionMap as $pattern => $action) {
            if ($this->matchRoute($key, $pattern)) {
                return $action;
            }
        }

        return null;
    }

    /**
     * 路由匹配
     */
    private function matchRoute($actual, $pattern)
    {
        // 简单的路由匹配，支持参数
        $pattern = str_replace('/', '\/', $pattern);
        $pattern = preg_replace('/\{[^}]+\}/', '[^\/]+', $pattern);
        $pattern = '/^' . $pattern . '$/';

        return preg_match($pattern, $actual);
    }

    /**
     * 获取操作描述
     */
    private function getActionDescription($action, Request $request)
    {
        $descriptions = [
            'login' => '用户登录',
            'logout' => '用户退出',
            'register' => '用户注册',
            'wechat_login' => '微信登录',
            'alipay_login' => '支付宝登录',
            'douyin_login' => '抖音登录',
            'bind_oauth' => '绑定第三方账号',
            'unbind_oauth' => '解绑第三方账号',
            'change_password' => '修改密码',
            'update_profile' => '更新个人资料',
            'delete_device' => '删除设备',
            'create_account' => '创建账号',
            'update_account' => '更新账号',
            'delete_account' => '删除账号',
            'copy_password' => '复制密码',
            'batch_delete_account' => '批量删除账号',
            'export_data' => '导出数据',
            'create_category' => '创建分类',
            'update_category' => '更新分类',
            'delete_category' => '删除分类',
            'feedback' => '用户反馈',
        ];

        return $descriptions[$action] ?? $action;
    }

    /**
     * 过滤敏感数据
     */
    private function filterSensitiveData($data)
    {
        if (!is_array($data)) {
            return $data;
        }

        $sensitiveKeys = [
            'password',
            'old_password',
            'new_password',
            'token',
            'access_token',
            'refresh_token',
            'username_encrypted',
            'password_encrypted',
            'notes_encrypted',
        ];

        foreach ($sensitiveKeys as $key) {
            if (isset($data[$key])) {
                $data[$key] = '***';
            }
        }

        return $data;
    }

    /**
     * 异步记录日志
     */
    private function asyncLog($logData)
    {
        try {
            // 可以使用队列来异步处理日志
            // 这里直接写入数据库
            UserLog::create($logData);
        } catch (\Exception $e) {
            // 记录日志失败不应该影响主流程
            // 可以记录到文件或其他地方
            trace('Log middleware error: ' . $e->getMessage());
        }
    }
}